﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UtilityToolsCollect.ObjectsLibrary.ProcessManage;

namespace FFmpegVideoClip.Lib
{
    /// <summary>
    /// 只要有释放或者取消操作，该类型的实例作废，是一次性实例，不可在取消操作后继续使用，内部状态不可恢复
    /// </summary>
    public class LimitedParallelPerformanceTaskScheduler : TaskScheduler, IDisposable
    {
        private static bool _ThreadStartSupported() { try { new Thread(() => { return; }).Start(); return true; } catch (PlatformNotSupportedException) { return false; } }
        public static readonly bool IsThreadStartSupported;
        private static readonly TimeSpan TasksMaximumIdleTime = TimeSpan.FromSeconds(5);
        static LimitedParallelPerformanceTaskScheduler() { IsThreadStartSupported = _ThreadStartSupported(); }

        //核心字段
        private int m_MaximumConcurrencyLevel;
        public override int MaximumConcurrencyLevel => m_MaximumConcurrencyLevel;
        private DateTime? PollingTaskStartTime;
        private bool autoCancel = false;
        private ConcurrentQueue<Task> TaskQueue = new();
        private ConcurrentDictionary<Task, int> TaskQueueDic = new();
        private ConcurrentDictionary<Task, int> RuningTasks = new();
        public IEnumerable<Task> Runings => RuningTasks.Keys;
        private CancellationTokenSource? cancellationTokenSource;
        private CancellationToken cancellationToken;
        private bool ForceEnableLongRunning;
        public bool IsActive => !disposedValue && !cancellationToken.IsCancellationRequested;
        public bool IsSaturated
        {
            get
            {
                if (_cpuPerformanceCountValues is null)
                    return RuningTasks.Count >= m_MaximumConcurrencyLevel;
                IEnumerable<float>? temp = _cpuPerformanceCountValues?.Where(p => p > 0);
                if (temp?.Any() != true)
                    return RuningTasks.Count >= m_MaximumConcurrencyLevel;
                return RuningTasks.Count >= m_MaximumConcurrencyLevel || temp.Average() >= m_MaximumConcurrencyLevel;
            }
        }

        //CPU占用侦测功能字段
        protected override IEnumerable<Task>? GetScheduledTasks() => TaskQueue;
        private System.Threading.PeriodicTimer? PollingTask;
        //private System.Threading.Timer? PollingTask;
        private CpuPerformanceCount? _cpuPerformanceCount;
        private float _CpuPerformanceLimit = 60;
        private float[]? _cpuPerformanceCountValues;
        private int CpuPerformanceCountIndex = 0;
        public float CpuPerformanceAverage
        {
            get
            {
                IEnumerable<float>? temp = _cpuPerformanceCountValues?.Where(p => p > 0);
                if (temp?.Any() != true)
                    return -1;
                return temp.Average();
            }
        }

        private bool IsCpuLimit
        {
            get
            {
                if (_cpuPerformanceCountValues == null)
                    return false;
                AddCpuPerformanceCount();
                try
                {
                    float cpuAverageValue = CpuPerformanceAverage;
                    return (cpuAverageValue > 0 ? cpuAverageValue : float.MaxValue) > _CpuPerformanceLimit;
                }
                catch (InvalidOperationException)
                { return true; }
            }
        }
        private void AddCpuPerformanceCount()
        {
            if (_cpuPerformanceCount is null)
                return;
            float value = _cpuPerformanceCount.Value;
            if (value < 1)
                return;
            _cpuPerformanceCountValues![CpuPerformanceCountIndex] = value;
            CpuPerformanceCountIndex = (CpuPerformanceCountIndex + 1) % _cpuPerformanceCountValues.Length;
        }

        public LimitedParallelPerformanceTaskScheduler(int maximumConcurrencyLevel = 0, CancellationToken? token = null, bool EnableCpuPerformanceCount = false, float CpuPerformanceLimit = 60f, int PerformanceCountCacheSize = 20, int PollingInterval = 250, bool forceEnableLongRunning = false, bool AutoCancel = false)
        {
            autoCancel = AutoCancel;
            m_MaximumConcurrencyLevel = maximumConcurrencyLevel > 0 ? maximumConcurrencyLevel : int.MaxValue;
            if (token is not null)
                cancellationToken = token.Value;
            else
            {
                cancellationTokenSource = new();
                cancellationToken = cancellationTokenSource.Token;
            }
            ForceEnableLongRunning = forceEnableLongRunning;
            if (!EnableCpuPerformanceCount)
                return;
            _cpuPerformanceCountValues = new float[PerformanceCountCacheSize];
            _cpuPerformanceCount = CpuPerformanceCount.Create(CpuPerformanceCount.PerformanceCountTypeEnum.InformationProcessorTime);
            _ = _cpuPerformanceCount.Value;
            _CpuPerformanceLimit = CpuPerformanceLimit;
            //PollingTask = new Timer(Polling, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(PollingInterval));
            PollingTask = new PeriodicTimer(TimeSpan.FromMilliseconds(PollingInterval));
            Task.Run(Polling);
        }

        protected override void QueueTask(Task task)
        {
            if (!IsActive)
                return;
            TaskQueue.Enqueue(task);
            TryExecuteNextTask();
        }

        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            if (!IsActive || taskWasPreviouslyQueued || TaskQueueDic.ContainsKey(task) || task.IsCanceled)//|| RuningTasks.Count >= MaximumConcurrencyLevel || IsCpuLimit
                return false;
            RuningTasks.TryAdd(task, default);
            ExecuteTask(task);
            return true;
        }

        private void ExecuteTask(Task task)
        {
            LogManage.WriteLineNewInfo($"调度信息：[执行], 等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务", true);
            try { TryExecuteTask(task); }
            finally
            {
                LogManage.WriteLineNewInfo($"调度信息：[完成], 等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务", true);
                if (IsActive)
                {
                    RuningTasks?.TryRemove(task, out _);
                    TryExecuteNextTask();
                }
            }
        }

        private void TryExecuteNextTask()
        {
            LogManage.WriteLineNewInfo($"调度信息：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue.Count}]个任务，执行中队列[{RuningTasks.Count}]个任务");
            if (_cpuPerformanceCount is not null)
                return;
            while (IsActive && RuningTasks.Count < MaximumConcurrencyLevel && !IsCpuLimit && TaskQueue.TryDequeue(out Task? TakeTask) && !TakeTask.IsCanceled)
                ExecuteNextTask(TakeTask);
        }

        private void ExecuteNextTask(Task TakeTask)
        {
            RuningTasks.TryAdd(TakeTask, default);

            if (ForceEnableLongRunning || (IsThreadStartSupported && (TakeTask.CreationOptions & TaskCreationOptions.LongRunning) != 0))
                new Thread(() => ExecuteTask(TakeTask)) { IsBackground = true, Name = "BackgroundThread" }.UnsafeStart();
            else
                ThreadPool.UnsafeQueueUserWorkItem(_ => ExecuteTask(TakeTask), (TakeTask.CreationOptions & TaskCreationOptions.PreferFairness) == 0);
        }

        private async Task Polling()
        {
            PollingTaskStartTime = DateTime.Now;
            try
            {
                while (IsActive && await PollingTask!.WaitForNextTickAsync(cancellationToken))
                {
                    if (IsActive && autoCancel && TaskQueue.Count < 1 && RuningTasks.Count < 1 && DateTime.Now - PollingTaskStartTime > TasksMaximumIdleTime)
                    {
                        cancellationTokenSource?.Cancel();
                        return;
                    }
                ReDequeue:
                    LogManage.WriteLineNewInfo($"调度信息：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue.Count}]个任务，执行中队列[{RuningTasks.Count}]个任务");
                    if (IsActive && RuningTasks.Count < MaximumConcurrencyLevel && !IsCpuLimit && TaskQueue.TryDequeue(out Task? TakeTask))
                    {
                        if (TakeTask.IsCanceled)
                            goto ReDequeue;
                        LogManage.WriteLineNewInfo($"调度信息：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue.Count}]个任务，执行中队列[{RuningTasks.Count}]个任务");
                        ExecuteNextTask(TakeTask);
                    }
                }
            }
            catch (OperationCanceledException) { }
        }


        #region IDisposable Support
        private volatile bool disposedValue = false;
        protected virtual void OnDispose()
        {
            if (!disposedValue)
            {
                disposedValue = true;
                if (cancellationTokenSource != null)
                {
                    if (!cancellationTokenSource.IsCancellationRequested)
                        cancellationTokenSource.Cancel();
                    cancellationTokenSource = null;
                }
                PollingTask?.Dispose();
                PollingTask = null;
                // PollingTask?.Dispose();
                // PollingTask = null!;
                if (_cpuPerformanceCount is not null)
                {
                    _cpuPerformanceCount.Dispose();
                    _cpuPerformanceCount = null;
                }
                _cpuPerformanceCountValues = null;
                TaskQueue.Clear();
                RuningTasks.Clear();
                TaskQueueDic.Clear();
            }
        }
        ~LimitedParallelPerformanceTaskScheduler() { OnDispose(); }
        public void Dispose() { OnDispose(); GC.SuppressFinalize(this); }
        #endregion
    }

}
